package top.zhangjianyong.blog.utils;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.zhangjianyong.blog.config.AntiHotlinkConfig;

/**
 * Referer验证工具类
 * 用于验证请求来源，实现防盗链功能
 *
 * @author zhangjianyong
 * @since 2024/12/19
 */
@Slf4j
@Component
public class RefererUtil {

    @Autowired
    private AntiHotlinkConfig config;

    /**
     * 验证Referer是否合法
     *
     * @param request HTTP请求
     * @return 是否合法
     */
    public boolean isValidReferer(HttpServletRequest request) {
        String referer = request.getHeader("Referer");
        
        // 如果没有Referer，可能是直接访问或书签访问
        if (StrUtil.isBlank(referer)) {
            log.warn("请求缺少Referer头: {}", request.getRequestURI());
            return config.isAllowEmptyReferer();
        }

        // 解析Referer中的域名
        String domain = extractDomain(referer);
        if (StrUtil.isBlank(domain)) {
            log.warn("无法解析Referer域名: {}", referer);
            return false;
        }

        // 检查域名是否在允许列表中
        boolean isValid = config.getAllowedDomains().stream()
            .anyMatch(allowed -> domain.equals(allowed) || domain.endsWith("." + allowed));

        if (!isValid) {
            log.warn("非法Referer访问: {} -> {}", referer, request.getRequestURI());
        }

        return isValid;
    }

    /**
     * 从URL中提取域名
     *
     * @param url URL
     * @return 域名
     */
    private static String extractDomain(String url) {
        try {
            // 移除协议部分
            String domain = url;
            if (domain.startsWith("http://")) {
                domain = domain.substring(7);
            } else if (domain.startsWith("https://")) {
                domain = domain.substring(8);
            }

            // 移除路径部分
            int slashIndex = domain.indexOf('/');
            if (slashIndex > 0) {
                domain = domain.substring(0, slashIndex);
            }

            // 移除端口号
            int colonIndex = domain.indexOf(':');
            if (colonIndex > 0) {
                domain = domain.substring(0, colonIndex);
            }

            return domain.toLowerCase();
        } catch (Exception e) {
            log.error("解析域名失败: {}", url, e);
            return null;
        }
    }

    /**
     * 检查是否为内部请求（用于API调用）
     *
     * @param request HTTP请求
     * @return 是否为内部请求
     */
    public boolean isInternalRequest(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        String xRequestedWith = request.getHeader("X-Requested-With");
        
        // 检查是否为AJAX请求
        if ("XMLHttpRequest".equals(xRequestedWith)) {
            return true;
        }
        
        // 检查User-Agent是否包含特定标识
        return StrUtil.isNotBlank(userAgent) && userAgent.contains("Blog-System");
    }
} 